#include "screen_space_renderer.h"
#include <glm/glm.hpp>
#include <GL/glew.h>
#include <vector>
#include "engine/utils/file_utils.h"


namespace kanon
{
    struct SSVertex
    {
        glm::vec2 pos;
        glm::vec2 uv;
    };

    ScreenspaceBuffer::ScreenspaceBuffer()
    {
        vao = 0;
        vbo = 0;

        // create vao and vbo
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);

        std::vector<SSVertex> vertices(6);
        vertices[0].pos = { -1.0f, -1.0f };
        vertices[0].uv = { 0.0f, 0.0f };
        vertices[1].pos = { -1.0f, 1.0f };
        vertices[1].uv = { 0.0f, 1.0f };
        vertices[2].pos = { 1.0f, 1.0f };
        vertices[2].uv = { 1.0f, 1.0f };
        
        vertices[3].pos = { -1.0f, -1.0f };
        vertices[3].uv = { 0.0f, 0.0f };
        vertices[4].pos = { 1.0f, 1.0f };
        vertices[4].uv = { 1.0f, 1.0f };
        vertices[5].pos = { 1.0f, -1.0f };
        vertices[5].uv = { 1.0f, 0.0f };

        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(SSVertex), vertices.data(), GL_STATIC_DRAW);

        // set vertex attributes
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(SSVertex), (void*)offsetof(SSVertex, pos));
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(SSVertex), (void*)offsetof(SSVertex, uv));
        glEnableVertexAttribArray(1);

        glBindVertexArray(0);
    }

    void ScreenspaceBuffer::Bind()
    {
        glBindVertexArray(vao);
    }

    void ScreenspaceBuffer::Unbind()
    {
        glBindVertexArray(0);
    }

    ScreenspaceRenderer::ScreenspaceRenderer()
    {
        std::string vertex_shader_path = FileUtils::getShaderPath("screen_space_renderer.vs");
        std::string fragment_shader_path = FileUtils::getShaderPath("screen_space_renderer.fs");
        shader = Shader::FromShaderFiles(vertex_shader_path, fragment_shader_path);
    }

    void ScreenspaceRenderer::Render(uint32_t texture_id)
    {
        ssbuffer.Bind();
        shader->Bind();

        shader->set_texture_slot("tex", 0);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture_id);

        glDrawArrays(GL_TRIANGLES, 0, 6);

        shader->Unbind();
        ssbuffer.Unbind();
    }
}
